// Infrastructure/Repositories/UserRepository.cs
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Linq.Expressions;
using UniversalAdmin.Domain.Entities;
using UniversalAdmin.Domain.Repositories;
using UniversalAdmin.Infrastructure.Data;

namespace UniversalAdmin.Infrastructure.Repositories
{
  public class UserRepository : BaseRepository<User>, IUserRepository
  {
    public UserRepository(UniversalAdminDbContext context) : base(context) { }

    public async Task<User?> GetByUsernameAsync(string username)
    {
      return await _context.Users
          .Include(u => u.UserRoles)
          .ThenInclude(ur => ur.Role)
          .FirstOrDefaultAsync(u => u.Username == username);
    }

    public async Task<User?> GetByEmailAsync(string email)
    {
      return await _context.Users
          .FirstOrDefaultAsync(u => u.Email == email);
    }

    public async Task<bool> IsUsernameExistsAsync(string username, int excludeUserId = 0)
    {
      return await _context.Users
          .AnyAsync(u => u.Username == username && u.Id != excludeUserId);
    }

    public async Task<bool> IsEmailExistsAsync(string email, int excludeUserId = 0)
    {
      return await _context.Users
          .AnyAsync(u => u.Email == email && u.Id != excludeUserId);
    }

    public async Task<IEnumerable<User>> GetUsersByRoleIdAsync(int roleId)
    {
      return await _context.Users
          .Where(u => u.UserRoles.Any(ur => ur.RoleId == roleId))
          .ToListAsync();
    }

    public async Task<IEnumerable<User>> GetUsersByRoleNameAsync(string roleName)
    {
      return await _context.Users
          .Where(u => u.UserRoles.Any(ur => ur.Role != null && ur.Role.Name == roleName))
          .ToListAsync();
    }

    public async Task<(IEnumerable<User> Items, int TotalCount)> GetPagedUsersAsync(
        string? keyword = null,
        bool? isActive = null,
        IEnumerable<int>? roleIds = null,
        int pageIndex = 1,
        int pageSize = 10,
        Expression<Func<User, bool>>? additionalPredicate = null,
        Func<IQueryable<User>, IOrderedQueryable<User>>? orderBy = null)
    {
      IQueryable<User> query = _context.Users
          .Include(u => u.UserRoles)
          .ThenInclude(ur => ur.Role);

      if (!string.IsNullOrWhiteSpace(keyword))
      {
        query = query.Where(u =>
            u.Username.Contains(keyword) ||
            u.Email.Contains(keyword) ||
            (u.Phone != null && u.Phone.Contains(keyword)));
      }

      if (isActive.HasValue)
      {
        query = query.Where(u => u.IsActive == isActive.Value);
      }

      if (roleIds != null && roleIds.Any())
      {
        query = query.Where(u => u.UserRoles.Any(ur => roleIds.Contains(ur.RoleId)));
      }

      if (additionalPredicate != null)
      {
        query = query.Where(additionalPredicate);
      }

      var totalCount = await query.CountAsync();

      if (orderBy != null)
      {
        query = orderBy(query);
      }
      else
      {
        query = query.OrderBy(u => u.Id);
      }

      var items = await query
          .Skip((pageIndex - 1) * pageSize)
          .Take(pageSize)
          .AsNoTracking()
          .ToListAsync();

      return (items, totalCount);
    }

    public async Task<User?> GetUserWithRolesAsync(int id)
    {
      return await _context.Users
          .Include(u => u.UserRoles)
          .ThenInclude(ur => ur.Role)
          .FirstOrDefaultAsync(u => u.Id == id);
    }

    public async Task<User?> GetUserWithRolesAndLogsAsync(int id)
    {
      return await _context.Users
          .Include(u => u.UserRoles)
          .ThenInclude(ur => ur.Role)
          .Include(u => u.OperationLogs)
          .FirstOrDefaultAsync(u => u.Id == id);
    }
  }
}